package ro.gillardon.business.priceservice.impl.train;

import javax.ejb.Stateless;

import org.apache.log4j.Logger;

import ro.gillardon.business.exception.BusinessException;
import ro.gillardon.business.priceservice.TrainPriceService;
import ro.gillardon.commons.Conditions;
import ro.gillardon.commons.Offers;
import ro.gillardon.commons.logger.BTPLogger;
import ro.gillardon.commons.mot.train.TrainConditions;
import ro.gillardon.commons.mot.train.TrainOfferDetails;

import com.thoughtworks.selenium.SeleniumException;

/**
 * Train Specific implementation for price service.
 *
 * @author davidl
 */
@Stateless
public class TrainPriceServiceEJB implements TrainPriceService {

  private static final Logger LOG = Logger.getLogger(TrainPriceServiceEJB.class);

  /**
   * Instantiates a new TrainPriceServiceEJB.
   */
  public TrainPriceServiceEJB() {
    // constructor without parameters
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public Offers<TrainOfferDetails> getOffers(final Conditions conditions) throws BusinessException {
    // check if conditions is of the correct type
    TrainConditions trainConditions = checkForCorrectType(conditions);

    // navigate through the page, fill all the input and return the raw HTML result table
    String rawResult = navigateThrouhPageAndGetRawResult(trainConditions);

    // parse the raw HTML and form the corresponding offer objects
    return DBahnResultParser.parse(rawResult, trainConditions);
  }

  /**
   * Wrapper method, where all the exceptions are caught and wrapped in {@link BusinessException}.
   *
   * @param conditions the entity which contains all the parameters to execute a query
   * @return After the search went through, the result table is returned, as raw HTML for later parsing
   * @throws BusinessException in case of the page was corrupted
   */
  private String navigateThrouhPageAndGetRawResult(final TrainConditions conditions) throws BusinessException {
    // navigator is set into the context of try with resource, so this always will be closed
    try (DBahnNavigator navigator = new DBahnNavigator()) {
      return executeSearchAndGetResults(conditions, navigator);
    } catch (SeleniumException e) {
      BTPLogger.error(LOG, e);
      throw new BusinessException(e);
    }
  }

  /**
   * Main method of the class here happens the important stuff. :D.
   *
   * @param conditions the entity which contains all the parameters to execute a query
   * @return After the search went through, the result table is returned, as raw HTML for later parsing
   * @throws BusinessException in case of the page was corrupted
   */
  private String executeSearchAndGetResults(final TrainConditions conditions, final DBahnNavigator navigator) {
    navigator.navigateToPage();
    navigator.fillRequiredInfo(conditions);
    navigator.search();
    return navigator.getResults();
  }

  /**
   * Checks if the parameter type is of the allowed type, if is, converts it to the concrete type,<br/>
   * if not, throws a {@link BusinessException}.
   *
   * @param conditions the object whose type is checked
   * @return the concrete type
   * @throws BusinessException if not of the required type
   */
  private TrainConditions checkForCorrectType(final Conditions conditions) throws BusinessException {
    if (!(conditions instanceof TrainConditions)) {
      throw new BusinessException();
    }
    return (TrainConditions) conditions;
  }
}
